package org.jiangy.authentication;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * 自定义一个认证入口点
 * <code>
 * 在Spring  Security中，AuthenticationEntryPoint是一个接口，它定义了当用户尝试访问受保护的资源但未通过身份验证时，Spring Security应该如何响应。这通常用于处理未授权的HTTP请求，例如当用户未登录就尝试访问一个需要认证的URL时。
 * <p>
 * AuthenticationEntryPoint的主要作用是定制未授权请求的响应。默认情况下，Spring Security可能会返回一个401（Unauthorized）状态码和默认的未授权页面。但是，在前后端分离的架构中，我们通常希望返回一个JSON格式的响应，以便前端可以据此进行相应的处理（比如显示登录表单）。
 * <p>
 * 以下是一个简单的AuthenticationEntryPoint实现示例，它返回一个JSON格式的响应：
 * <p>
 * java
 * 复制
 * import javax.servlet.http.HttpServletRequest;
 * import javax.servlet.http.HttpServletResponse;
 * import javax.servlet.ServletException;
 * import java.io.IOException;
 * import java.io.PrintWriter;
 * <p>
 * import org.springframework.security.core.AuthenticationException;
 * import org.springframework.security.web.AuthenticationEntryPoint;
 * import org.springframework.stereotype.Component;
 *
 * @author <a href="mailto:jiangliu0316@outlook.com" rel="nofollow">蒋勇</a>
 * @Component public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
 * @Override public void commence(HttpServletRequest request,
 * HttpServletResponse response,
 * AuthenticationException authException) throws IOException, ServletException {
 * <p>
 * // 设置响应内容类型
 * response.setContentType("application/json");
 * response.setCharacterEncoding("UTF-8");
 * <p>
 * // 设置响应状态码为401
 * response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
 * <p>
 * // 发送JSON响应
 * PrintWriter out = response.getWriter();
 * out.print("{\"error\":\"Unauthorized\",\"message\":\"Access Denied\"}");
 * out.flush();
 * }
 * }
 * <p>
 * <p>
 * 然后，你需要在你的Spring Security配置中注册这个CustomAuthenticationEntryPoint：
 * <p>
 * java
 * 复制
 * @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {
 * @Autowired private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
 * @Override protected void configure(HttpSecurity http) throws Exception {
 * http
 * // ... 其他配置 ...
 * .exceptionHandling()
 * .authenticationEntryPoint(customAuthenticationEntryPoint)
 * // ... 其他配置 ...
 * ;
 * }
 * <p>
 * // ... 其他配置 ...
 * }
 * <p>
 * <p>
 * 这样，当用户尝试访问受保护的资源但未通过身份验证时，Spring Security就会调用你的CustomAuthenticationEntryPoint，并返回你定义的JSON响应。前端可以捕获这个响应，并据此显示登录表单或进行其他处理。
 * </code>
 * <p>创建时间: 2024/8/13 </p>
 */
@Slf4j
@Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {

        // 设置响应内容类型
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        // 设置响应状态码为401
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        // 发送JSON响应
        PrintWriter out = response.getWriter();
        out.print("{\"error\":\"Unauthorized\",\"message\":\"%s\"}".formatted(authException.getMessage()));
        out.flush();
    }
}
